/* typehints:start */
import { GameRoot } from '../root.js';
import { Npc } from '../npcs/npc.js';
/* typehints:end */

import { createLogger } from '../../core/utils/logging.js';
import { globalConfig } from '../../config/global.js';
import map from './defines/map.json'
import { MapClip } from './map_clip.js';
import NpcModules from '../npcs/get_npc.js';
import GoodModules from '../goods/get_good.js';
import { getDayTime } from '../time.js';
import { matchArray, ObjectValArrOnly } from '../../core/utils/utils.js';
import { compressionPrefix } from '../../core/utils/read_write_proxy.js';
import { decompressX64 } from '../../core/utils/lzstring.js';

export const worlds = {};

const logger = createLogger('game/world_map')

let mapData = {};

/**
 * 管理所有物品，生灵，地图
 */
export class WorldMap{
  constructor(root){
    /** @type {GameRoot} */
    this.root = root;
    this.worlds = worlds;

    this.npcs = [];
    this.goods = [];

    this.generates = [];
  }

  initialize(){
    mapData = JSON.parse(decompressX64(map.data));
    // 解析地图文件
    this.createMapClip()
    this.createNpc(mapData.npcs);
    this.createGood(mapData.goods);

    Object.keys(this.root.itemData.extraGoods).forEach(key => {
      this.createExtraGood(key, this.root.itemData.extraGoods[key]);
    })
  }

  createMapClip(){
    let world = mapData.world;

    for(let i = 0; i < world.length; i++){
      let data = world[i];
      this.worlds[data.worldPos] = data;
    }
  }

  createNpc(data, isGenerate = true){
    let npcs = data;

    for(let i = 0; i < npcs.length; i++){
      let data = npcs[i];

      let item = NpcModules[data.key];
      if(globalConfig.debug.ItemOrNpcNoFoundError){
        assert(item, `${data.key} Npc不存在`)
        return;
      } else if(!item){
        return;
      }

      if(data.generate && isGenerate){
        data.type = 'npc';
        this.generates.push(data);
      } else {
        let npc = new NpcModules[data.key](this.root, data.storeId, data.peopleAttr, data.attr, !isGenerate);
        npc.initialize();
        this.npcs.push(npc);
      }
    }
  }

  /**
   * 
   * @param {*} data 
   * @param {*} loadGenData 是否需要加载生成物品数据
   * @returns 
   */
  createGood(data, loadGenData = true){
    let goods = data;

    for(let i = 0; i < goods.length; i++){
      let data = goods[i];

      let item = GoodModules[data.key];
      if(globalConfig.debug.ItemOrNpcNoFoundError){
        assert(item, `${data.key} Good不存在`)
        return;
      } else if(!item){
        return;
      }

      if(data.generate && loadGenData){
        data.type = 'good'
        this.generates.push(data);
      } else {
        let good = new GoodModules[data.key](this.root, data.storeId, data.goodAttr, !loadGenData);
        good.initialize(data.key);
        this.goods.push(good);
      }
    }
  }

  createExtraGood(id, goodData){
    let data = {
      key: goodData.key,
      storeId: id,
      goodAttr: goodData.attr
    };

    this.createGood([data]);
    // 通知游戏内的显示重新渲染
    if(this.root.hud){
      this.root.hud.parts.worldPage.renderAllPeopleAndGoods();
    }
  }

  /**
   * 获取一样物品的实例
   * @param {*} key 物品的key
   * @param {*} data 物品的多样数据
   * @returns 
   */
  getGood(key, attr = {}, data = {}){
    /** @type {Goods} */
    let good = GoodModules[key];
    if(good){
      attr = { data: {}, ...attr }
      attr.data = { ...attr.data, ...data }
      good = new good(this.root, null, attr);
      good.initialize(key);
      return good;
    } else {
      this.root.gameState.dialogs.showWarning('物品丢失', `<${key}>丢失了，请联系开发者调整。`);
    }
    return false;
  }

  getCurrentNpcs(){
    return this.getNpcs(this.root.mainPlayer.data.worldPos, this.root.mainPlayer.data.mapPos);
  }

  getCurrentGoods(){
    return this.getGoods(this.root.mainPlayer.data.worldPos, this.root.mainPlayer.data.mapPos);
  }

  getNpcs(worldPos, mapPos){
    return this.npcs.filter(npc => {
      if(npc.people.data.worldPos.join(',') == worldPos.join(',')
        && (!mapPos || npc.people.data.mapPos.join(',') == mapPos.join(','))){
          return true;
      }
      return false;
    }).filter(item => item.attr.isLive)
  }

  getIdNpcs(storeId){
    return this.npcs.filter(item => {
      return item.storeId == storeId;
    }).filter(item => item.attr.isLive)
  }

  getGoods(worldPos, mapPos){
    return this.goods.filter(good => {
      if(good.attr.worldPos.join(',') == worldPos.join(',')
        && (!mapPos || good.attr.mapPos.join(',') == mapPos.join(','))){
          return true;
      }
      return false;
    }).filter(item => item.attr.isLive)
  }

  getIdGoods(storeId){
    return this.goods.filter(item => {
      return item.storeId == storeId;
    }).filter(item => item.attr.isLive)
  }

  // 获得对应地址的地图块, 同时实例化对应地图块
  getMapClip(pos){
    let data = this.worlds[pos];

    if(data instanceof MapClip){
      return data;
    } else {
      let mapClip = new MapClip(this.root, data.worldName, data.worldPos);

      data.map.map(item => {
        mapClip.add(item);
      })
      this.worlds[pos] = mapClip;
      this.createInitItem(pos)

      return mapClip;
    }
  }

  // 获得地图块指定位置的区域
  getMapSite(mapClip, pos){
    return mapClip.map[pos];
  }

  createInitItem(worldPos){
    let npcs = [];
    let goods = [];

    this.generates.filter(item => {
      let itemPos = null;
      if(item.type == 'good'){
        itemPos = item.goodAttr.worldPos;
      }
      if(item.type == 'npc'){
        itemPos = item.peopleAttr.worldPos;
      }

      if(!itemPos || (
        itemPos[0] == worldPos[0] && itemPos[1] == worldPos[1]
      )) return true;
    }).forEach(item => {
      let storeData = this.root.worldData.mapItem[item.storeId];
      // 已经生成的内容直接在初始化时生成
      if(!storeData || (!storeData.isCreate && storeData.num <= 0)) return;
      
      if(item.type === 'good'){
        for(let i = 0; i < storeData.num; i++){
          goods.push(ObjectValArrOnly(item, ['mapPos']));
        }
      }

      if(item.type === 'npc'){
        for(let i = 0; i < storeData.num; i++){
          npcs.push(ObjectValArrOnly(item, ['mapPos']));
        }
      }
    })

    if(goods.length > 0 || npcs.length > 0){
      this.createGood(goods, false);
      this.createNpc(npcs, false);

      logger.log(`Init 👶 生成Npc: ${npcs.length}项, Good: ${goods.length}项`)

      // 通知游戏内的显示重新渲染
      this.root.hud.parts.worldPage.renderAllPeopleAndGoods();
    }
  }

  /**
   * 生成对应世界地区的所有内容
   * @param {*} worldPos 
   */
  createItem(worldPos){
    let npcs = [];
    let goods = [];

    this.generates.filter(item => {
      let itemPos = null;
      if(item.type == 'good'){
        itemPos = item.goodAttr.worldPos;
      }
      if(item.type == 'npc'){
        itemPos = item.peopleAttr.worldPos;
      }

      if(!itemPos || (
        itemPos[0] == worldPos[0] && itemPos[1] == worldPos[1]
      )) return true;
    }).forEach(item => {
      let storeData = { ...{
        createDayTime: -item.recoveryDayTime,
        isCreate: true
      }, ...(this.root.worldData.mapItem[item.storeId] || {})};
      
      // 生成时间间隔小于等于0并且已经生成了将不会继续生成
      if(item.recoveryDayTime <= 0 && !storeData.isCreate) return;

      if(this.root.worldData.time - storeData.createDayTime < item.recoveryDayTime) return;
      storeData.createDayTime = this.root.worldData.time;
      storeData.num = item.generateMax;
      
      if(item.type === 'good'){
        let num = item.generateMax - this.getIdGoods(item.storeId).length;

        for(let i = 0; i < num; i++){
          goods.push(ObjectValArrOnly(item, ['mapPos']));
        }
      }

      if(item.type === 'npc'){
        let num = item.generateMax - this.getIdNpcs(item.storeId).length;

        for(let i = 0; i < num; i++){
          npcs.push(ObjectValArrOnly(item, ['mapPos']));
        }
      }

      // 仅生成一次，可以用于稀有物品，这种物品在游戏中仅生成一次。
      if(item.recoveryDayTime <= 0) storeData.isCreate = false;
      this.root.worldData.mapItem[item.storeId] = storeData;
    })

    if(goods.length > 0 || npcs.length > 0){
      this.createGood(goods, false);
      this.createNpc(npcs, false);

      logger.log(`👶 生成Npc: ${npcs.length}项, Good: ${goods.length}项`)
      this.root.saveWorldData();

      // 通知游戏内的显示重新渲染
      this.root.hud.parts.worldPage.renderAllPeopleAndGoods();
    }
  }

  update(){
    // 游戏内每一天检测是否需要生成新的游戏内容
    this.root.time.run('everyDay-createItem', () => {
      let worldPos = this.root.mainPlayer.data.worldPos;
      if(worldPos){
        this.createItem(worldPos);
      }
    }, getDayTime())

    let npcs = this.getNpcs(this.root.mainPlayer.data.worldPos);
    // 对当前npc进行更新
    npcs.map(npc => {
      npc.update();
    })

    let goods = this.getGoods(this.root.mainPlayer.data.worldPos);
    goods.map(good => {
      good.update();
    })
  }
}
